<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>flowchart</title>
  <link rel="stylesheet" type="text/css" href="css/style.css">
  <script src="js/jsplumb.js"></script>
  <script src="js/jquery.js"></script>

</head>

<body onselectstart="return false;" unselectable="on">
<input type="hidden" id="projectName">
<input type="hidden" id="unitName">
<!-- Menu -->
<div id="menuContainer" class="menu">
  <p style="text-align: center;">操作</p>
  <div class="menu-button-container">
    <div class="button-add-task button menu-button ele-draggable" id="button-add-task" draggable="true">添加任务</div>
    <div class="button-add-decision button menu-button ele-draggable" id="button-add-decision" draggable="true">添加决定
    </div>

    <div>
      <button id="saveButton" class="button menu-button">保存</button>
      <button id="resetButton" class="button menu-button" style="float: right;">重置</button>
    </div>
  </div>
</div>
<div id="canvas" style="width:100%; min-height: 700px; background: #d6d6d6; margin-bottom: 6px;">
</div>
</body>
<script>

const canvasId = '#canvas';
let offsetX = 0;
let offsetY = 0;
let numberOfElements = 0;
jsPlumb.importDefaults({
  MaxConnections: 1,
  Endpoint: ['Dot', { radius: 8 }],
  EndpointStyle: { fill: '#8ea6db' },
  EndpointHoverStyle: { fill: '#3d6ede' },
  PaintStyle: { stroke: '#e85050', strokeWidth: 2 },
  HoverPaintStyle: { stroke: '#9e1b1b', strokeWidth: 2 },
  Connector: [
    'Flowchart',
    {
      gap: 0,
      cornerRadius: 5,
      alwaysRespectStubs: true,
      // midpoint: 0,
      // stub: 2,
      // cornerRadius: 2
    },
  ],
  ConnectionOverlays: [
    ['Arrow', {
      location: 1,
      id: 'arrow',
      length: 10,
      width: 14,
      foldback: 0.6,
    }],
  ],
});

// 不允许自己连接自己
jsPlumb.bind('beforeDrop', ({ sourceId, targetId }, originalEvent) => {
  if (sourceId == targetId) {
    return false;
  }
  return true;
});

// 重置按钮
$('#cleanButton').on('click', () => {
  jsPlumb.empty('canvas');
});

$('#loadButton').click(() => {
  resetPage();
});

$(canvasId).on('click', '.button-remove', function () {
  const parentnode = $(this)[0].parentNode.parentNode;
  jsPlumb.deleteConnectionsForElement(parentnode);
  jsPlumb.removeAllEndpoints(parentnode);
  $(parentnode).remove();
});

$(canvasId).on('click', '.button-edit', function () {
  const node = $(this)[0].parentNode.parentNode;
  if (jshelper) {
    const projectName = $('#projectName').val();
    const unitName = $('#unitName').val();
    jshelper.switch_page(node.id, projectName, unitName);
  }
});

$('.ele-draggable').on('dragstart', (ev, ff) => {
  const { originalEvent, target } = ev;
  offsetX = ev.offsetX;
  offsetY = ev.offsetY;
  originalEvent.dataTransfer.setData('text', target.id);
});

$(canvasId).on('dragover', ev => {
  ev.preventDefault();
});

$(canvasId).on('drop', ev => {
  const { originalEvent } = ev;
  const posX = ev.pageX - offsetX; //需要减去鼠标的偏移值
  const posY = ev.pageY - offsetY;

  if (!originalEvent.dataTransfer) return; // 连线时会触发 drop 事件，值为 undfined

  const data = originalEvent.dataTransfer.getData('text');
  if (data == 'button-add-task') {
    addNode({ posX, posY, scenario: 'task' });
  }

  if (data == 'button-add-decision') {
    addNode({ posX, posY, scenario: 'decision' });
  }

  // $(canvasId).on("click", ".button-edit", function () {
  //     const node = $(this)[0]
  //     if (jshelper) {
  //         jshelper.switch_page(node.id)
  //     }
  // });
});

function addStartNode(point) {
  const startPointDiv = `
            <div id="startpoint"
                class="window startpoint point node"
                style="left: ${point.x}px; top:${point.y}px;"
                data-nodetype="startpoint">开始</div>`;
  $(startPointDiv).appendTo(canvasId);
  jsPlumb.addEndpoint('startpoint', {
    uuid: 'startpoint-bm-out',
    isSource: true,
    isTarget: false,
    anchors: ['BottomCenter'],
    maxConnections: 1,
  });
  jsPlumb.draggable('startpoint');
}

function addEndNode(point) {
  const endPointDiv = `
            <div id="endpoint" class="window endpoint point node" style="left: ${point.x}px; top:${point.y}px;"
             data-nodetype="endpoint">结束</div>`;
  $(endPointDiv).appendTo(canvasId);
  jsPlumb.addEndpoint(
    'endpoint',
    {
      uuid: 'endpoint-tm-in',
      isSource: false,
      isTarget: true,
      anchor: ['TopCenter'],
      endpoint: ['Rectangle', { width: 12, height: 12 }],
      maxConnections: -1,
    },
  );
  jsPlumb.draggable('endpoint');
}

function addNode({ id, posX, posY, scenario, name }) {
  // const projectName = $("#projectName").val()
  // const unitName = $("#projectName").val()
  if (typeof id == 'undefined') {
    numberOfElements++;
    id = 'node' + numberOfElements;
  }
  // <div className="details-container">
  //     <input className="detail-text"/>
  // </div>
  const taskNode = `
                <div class="window task node" id="${id}" data-nodetype="task" style="left: ${posX}px; top: ${posY}px;">
                    <div class="ctrl-container">
                        <div class="button-remove"/>
                        <div id="edit_${id}" class="button-edit"/>
                    </div>
                   <div class="djs-direct-editing-content details-container" contenteditable="true" onclick="editDiv(event)">
                       ${name ? name : ''}
                    </div>
                </div>`;

  const decisionNode = `
                <div class="window decision node" id="${id}" data-nodetype="decision" style="left: ${posX}px; top: ${posY}px;">
                    <div class="ctrl-container">
                        <div class="button-remove"></div>
                        <div id="edit_${id}" class="button-edit">
                    </div>
                    </div>
                    <div class="djs-direct-editing-content details-container" contenteditable="true" onclick="editDiv(event)"
                         style="transform: rotate(45deg);top: 30%; min-height: 20px; font-size: 12px; text-align: center;">
                         ${name ? name : ''}
                    </div>
                </div>`;

  if (scenario == 'task') {
    $(taskNode).appendTo(canvasId);
  }

  if (scenario == 'decision') {
    $(decisionNode).appendTo(canvasId);
  }

  addEndpoint({ id, scenario });
  jsPlumb.draggable(id);
}

function addEndpoint({ id, scenario }) {
  if (scenario == 'task') {
    jsPlumb.addEndpoint(
      id,
      {
        uuid: id + '-tm-in',
        isTarget: true,
        anchor: 'TopCenter',
        endpoint: ['Rectangle', { width: 12, height: 12 }],
        maxConnections: -1,
      },
    );

    jsPlumb.addEndpoint(
      id,
      {
        uuid: id + '-bm-out',
        isSource: true,
        anchor: 'BottomCenter',
        endpoint: ['Dot', { radius: 8 }],
        maxConnections: 1,
      },
    );
  }

  if (scenario == 'decision') {
    jsPlumb.addEndpoint(
      id, {
        uuid: id + '-tm-in',
        isTarget: true,
        anchor: [0.5, -0.2],
      }, {
        endpoint: ['Rectangle', { width: 12, height: 12 }],
      },
    );

    jsPlumb.addEndpoint(
      id, {
        uuid: id + '-lm-out',
        isSource: true,
        anchor: [-0.2, 0.5],
      },
    );

    jsPlumb.addEndpoint(
      id, {
        uuid: id + '-rm-out',
        isSource: true,
        anchor: [1.2, 0.5],
      },
    );
  }
}

function flowchartData() {
  const nodes = [];
  // 保存数据用
  $('.node').each((idx, elem) => {
    const $elem = $(elem);
    // 获取当前节点名称
    let divContainer = $elem.find('.details-container')[0];
    let name = null;
    if (divContainer) {
      name = divContainer.innerText;
    }
    nodes.push({
      blockId: $elem.attr('id'),
      nodetype: $elem.attr('data-nodetype'),
      positionX: parseInt($elem.css('left'), 10),
      positionY: parseInt($elem.css('top'), 10),
      name,
    });
  });

  const connections = [];
  $.each(jsPlumb.getConnections(), (idx, connection) => {
    connections.push({
      uuids: connection.getUuids(),
    });
  });

  const flowChart = {};
  // flowChart.projectName = $("#project_name").val()
  // flowChart.unitName = $("#unit_name").val()
  flowChart.nodes = nodes;
  flowChart.connections = connections;
  flowChart.numberOfElements = numberOfElements;
  const flowChartJson = JSON.stringify(flowChart);
  return flowChartJson;
}

// 画面初始化
function loadFlowchart(flowChartJson) {
  resetPage();
  if (!flowChartJson || flowChartJson == 'null' || flowChartJson == 'None') {
    addStartNode({ x: 300, y: 20 });
    addEndNode({ x: 300, y: 400 });
    return;
  }
  const flowChart = JSON.parse(flowChartJson);
  const nodes = flowChart.nodes;
  if (!nodes) {
    addStartNode({ x: 300, y: 20 });
    addEndNode({ x: 300, y: 400 });
    return;
  }
  let projectName = flowChart.project_name;
  let unitName = flowChart.unit_name;
  $('#projectName').attr('value', projectName);
  $('#unitName').attr('value', unitName);

  $.each(nodes, (index, elem) => {
    const id = elem.blockId;
    const posX = elem.positionX;
    const posY = elem.positionY;
    const name = elem.name;
    if (elem.nodetype == 'startpoint') {
      addStartNode({ x: posX, y: posY });
    }

    if (elem.nodetype == 'endpoint') {
      addEndNode({ x: posX, y: posY });
    }

    if (elem.nodetype == 'task') {
      addNode({ id, posX, posY, scenario: 'task', name });
    }

    if (elem.nodetype == 'decision') {
      addNode({ id, posX, posY, scenario: 'decision', name });
    }

    repositionElement({ id, posX, posY });
  });

  const connections = flowChart.connections;
  $.each(connections, function (index, elem) {
    jsPlumb.connect({
      uuids: elem.uuids,
    });
  });
  numberOfElements = flowChart.numberOfElements;
}

function repositionElement({ id, posX, posY }) {
  $(`#${id}`).css('left', posX);
  $(`#${id}`).css('top', posY);
  jsPlumb.repaint(id);
}

function disablePage() {
  jsPlumb.empty('canvas');
  $('#menuContainer').hide();
}


function resetPage(points) {
  jsPlumb.empty('canvas');
  $('#menuContainer').show();
}

$(document).ready(function () {
  // disablePage();
  loadFlowchart();
});

function editDiv(event) {
  $(event.currentTarget).focus();
}
</script>

</html>
